/**
 * Notes: 日志操作函数
 * Ver : CCMiniCloud Framework 2.34.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat)
 * Date: 2021-06-12 04:00:00 
 */
const timeUtil = require('./time_util.js');

// 日志缓存
const LOG_CACHE = {
    data: [],        // 缓存数据
    maxSize: 50,     // 最大缓存条数
    maxContentLength: 500, // 最大内容长度
    enabled: true    // 是否启用缓存
};

// 采样率控制 (0-100)
const SAMPLING_RATES = {
    DEBUG: 10,  // DEBUG级别日志采样10%
    INFO: 30,   // INFO级别日志采样30%
    WARN: 80,   // WARN级别日志采样80%
    ERROR: 100, // ERROR级别日志采样100%
    FATAL: 100  // FATAL级别日志采样100%
};

class LogUtil {

	constructor(level = 'info', options = {}) {
		this.logOut = ''; // 输出日志内容
		this.maxOutputSize = options.maxOutputSize || 10240; // 最大输出大小10KB
		this.samplingEnabled = options.samplingEnabled !== false; // 是否启用采样
		this.compressionEnabled = options.compressionEnabled !== false; // 是否启用压缩
        this.output = options.output !== false; // 是否输出到控制台

		level = level.toLowerCase();
		if (level == 'err') level = 'error';

		switch (level) {
			case 'debug':
				level = LogUtil.LEVEL.DEBUG;
				break;
			case 'info':
				level = LogUtil.LEVEL.INFO;
				break;
			case 'warn':
				level = LogUtil.LEVEL.WARN;
				break;
			case 'error':
				level = LogUtil.LEVEL.ERROR;
				break;
			case 'fatal':
				level = LogUtil.LEVEL.FATAL;
				break;
			case 'none':
				level = LogUtil.LEVEL.NONE;
				break;
			default:
				level = LogUtil.LEVEL.INFO;
		}
		this.level = level;
	}

	// 是否需要采样
	_shouldSample(level) {
	    if (!this.samplingEnabled) return true;
	    
	    let rate = 100;
	    switch(level) {
	        case LogUtil.LEVEL.DEBUG:
	            rate = SAMPLING_RATES.DEBUG;
	            break;
	        case LogUtil.LEVEL.INFO:
	            rate = SAMPLING_RATES.INFO;
	            break;
	        case LogUtil.LEVEL.WARN:
	            rate = SAMPLING_RATES.WARN;
	            break;
	        case LogUtil.LEVEL.ERROR:
	            rate = SAMPLING_RATES.ERROR;
	            break;
	        case LogUtil.LEVEL.FATAL:
	            rate = SAMPLING_RATES.FATAL;
	            break;
	    }
	    
	    return Math.random() * 100 <= rate;
	}

	// 压缩日志内容
	_compressContent(content, ex = '') {
	    if (!this.compressionEnabled) return content;
	    
	    // 截断过长内容
	    if (typeof content === 'string' && content.length > LOG_CACHE.maxContentLength) {
	        content = content.substring(0, LOG_CACHE.maxContentLength) + '...';
	    }
	    
	    // 处理异常对象
	    if (ex) {
	        if (typeof ex === 'object') {
	            try {
	                // 只保留关键信息
	                const keys = Object.keys(ex);
	                if (keys.length > 10) {
	                    const importantEx = {};
	                    ['message', 'code', 'name', 'stack'].forEach(key => {
	                        if (ex[key]) importantEx[key] = ex[key];
	                    });
	                    // 添加部分自定义属性
	                    for (let i = 0; i < 7 && i < keys.length; i++) {
	                        if (!importantEx[keys[i]]) {
	                            importantEx[keys[i]] = ex[keys[i]];
	                        }
	                    }
	                    ex = importantEx;
	                }
	                
	                // 限制错误堆栈长度
	                if (ex.stack && ex.stack.length > 500) {
	                    ex.stack = ex.stack.substring(0, 500) + '...';
	                }
	                
	                return content + " " + JSON.stringify(ex);
	            } catch (e) {
	                return content + " [无法序列化的异常对象]";
	            }
	        }
	        return content + " " + ex;
	    }
	    
	    return content;
	}

	// 添加日志到缓存
	_addToCache(level, content, ex) {
	    if (!LOG_CACHE.enabled) return;
	    
	    // 保持缓存大小限制
	    if (LOG_CACHE.data.length >= LOG_CACHE.maxSize) {
	        LOG_CACHE.data.shift(); // 移除最旧的日志
	    }
	    
	    // 添加到缓存
	    LOG_CACHE.data.push({
	        time: this._getTime(),
	        level,
	        content,
	        ex: ex ? (typeof ex === 'object' ? JSON.stringify(ex) : ex) : ''
	    });
	}

	debug(str, ex = '') {
		if (this.level > LogUtil.LEVEL.DEBUG) return;
		if (!this._shouldSample(LogUtil.LEVEL.DEBUG)) return;

		const content = this._compressContent(str, ex);
		if (this.output) {
		    console.debug('[' + this._getTime() + '] DEBUG: ' + content);
		}
		
		this._addToCache('DEBUG', str, ex);
		
		// 限制输出大小
		if (this.logOut.length < this.maxOutputSize) {
		    this.logOut += "######" + '[' + this._getTime() + '] DEBUG: ' + content;
		}
	}

	info(str, ex = '') {
		if (this.level > LogUtil.LEVEL.INFO) return;
		if (!this._shouldSample(LogUtil.LEVEL.INFO)) return;

		const content = this._compressContent(str, ex);
		if (this.output) {
		    console.log('[' + this._getTime() + '] INFO: ' + content);
		}
		
		this._addToCache('INFO', str, ex);

		// 限制输出大小
		if (this.logOut.length < this.maxOutputSize) {
		    this.logOut += "######" + '[' + this._getTime() + '] INFO: ' + content;
		}
	}

	warn(str, ex = '') {
		if (this.level > LogUtil.LEVEL.WARN) return;
		if (!this._shouldSample(LogUtil.LEVEL.WARN)) return;

		const content = this._compressContent(str, ex);
		if (this.output) {
		    console.warn('[' + this._getTime() + '] WARN: ' + content);
		}
		
		this._addToCache('WARN', str, ex);

		// 限制输出大小
		if (this.logOut.length < this.maxOutputSize) {
		    this.logOut += "######" + '[' + this._getTime() + '] WARN: ' + content;
		}
	}

	error(str, ex = '') {
		if (this.level > LogUtil.LEVEL.ERROR) return;
		// 错误级别始终记录，不采样

		const content = this._compressContent(str, ex);
		if (this.output) {
		    console.error('[' + this._getTime() + '] ERROR: ' + content);
		}
		
		this._addToCache('ERROR', str, ex);

		// 限制输出大小
		if (this.logOut.length < this.maxOutputSize) {
		    this.logOut += "######" + '[' + this._getTime() + '] ERROR: ' + content;
		}
	}

	fatal(str, ex = '') {
		if (this.level > LogUtil.LEVEL.FATAL) return;
		// 致命错误始终记录，不采样

		const content = this._compressContent(str, ex);
		if (this.output) {
		    console.error('[' + this._getTime() + '] FATAL: ' + content);
		}
		
		this._addToCache('FATAL', str, ex);

		// 限制输出大小
		if (this.logOut.length < this.maxOutputSize) {
		    this.logOut += "######" + '[' + this._getTime() + '] FATAL: ' + content;
		}
	}

	_getTime() {
		return timeUtil.time('Y-M-D h:m:s');
	}

	err(str) {
		this.error(str);
	}

	getLogOut() {
		return this.logOut;
	}
	
	// 获取缓存日志
	getLogCache() {
	    return LOG_CACHE.data;
	}
	
	// 清空缓存
	clearLogCache() {
	    LOG_CACHE.data = [];
	}
	
	// 设置缓存配置
	static setLogCacheConfig(config = {}) {
	    if (config.maxSize !== undefined) {
	        LOG_CACHE.maxSize = config.maxSize;
	    }
	    if (config.enabled !== undefined) {
	        LOG_CACHE.enabled = config.enabled;
	    }
	    if (config.maxContentLength !== undefined) {
	        LOG_CACHE.maxContentLength = config.maxContentLength;
	    }
	}
	
	// 设置采样率
	static setSamplingRates(rates = {}) {
	    Object.keys(rates).forEach(level => {
	        if (SAMPLING_RATES[level] !== undefined) {
	            SAMPLING_RATES[level] = Math.min(100, Math.max(0, rates[level]));
	        }
	    });
	}

}

LogUtil.LEVEL = {
	DEBUG: 10,
	INFO: 20,
	WARN: 30,
	ERROR: 40,
	FATAL: 50,
	NONE: 100,
};

module.exports = LogUtil;